package displayboardinfo.entities;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

/**
 * Klasa reprezentująca pojedynczą wizytę.
 * 
 * @author Artur Jaworski
 */
@Entity
@Table ( name = "Visits" )
@XmlRootElement
@XmlType(propOrder = { "id", "room", "patient", "date", "duration", "estimatedEntry" })
public class Visit {
	@Id
	@Column ( name = "id" )
	@GeneratedValue(strategy=GenerationType.AUTO)
	protected long id;
	
	@ManyToOne ( cascade = CascadeType.ALL )
	@JoinColumn ( name = "id_room", nullable = false )
	protected Room room;
	
	@ManyToOne
	@JoinColumn ( name = "id_patient", nullable = false )
	protected Patient patient;
	
	@Column ( name = "date", nullable = false )
	protected Date date;
	
	@Column ( name = "duration", nullable = false )
	protected Date duration;

	@Column ( name = "estimated_entry", nullable = false )
	protected Date estimatedEntry;
	
	/**
	 * Domyślny konstruktor bezargumentowy.
	 */
	public Visit() {
	
	}

	/**
	 * Pobranie unikalnego numeru ID okresu przyjęć gabinetu. 
	 * 
	 * @return unikalny numer ID
	 */
	public long getId() {
		return id;
	}

	/**
	 * Ustawienie unikalnego numeru ID okresu przyjęć gabinetu.
	 * Ręczne ustawianie numeru ID powinno być zawsze robione z rozwagą. 
	 * 
	 * @param id unikalny numer ID
	 */
	public void setId(long id) {
		this.id = id;
	}
	
	/**
	 * Pobranie obiektu gabinetu, w którym odbywa się wizyta.
	 * 
	 * @return gabinet, w którym odbywa się wizyta
	 */
	public Room getRoom() {
		return room;
	}

	/**
	 * Ustawienie obiektu gabinetu, w którym odbywa się wizyta.
	 * 
	 * @param room gabinet, w którym odbywa się wizyta
	 */
	public void setRoom(Room room) {
		this.room = room;
	}

	/**
	 * Pobranie obiektu pacjenta, który jest zapisany na wizytę.
	 * 
	 * @return pacjent, który jest zapisany na wizytę
	 */
	public Patient getPatient() {
		return patient;
	}

	/**
	 * Ustawienie obiektu pacjenta, który jest zapisany na wizytę.
	 * 
	 * @param patient pacjent, który jest zapisany na wizytę
	 */
	public void setPatient(Patient patient) {
		this.patient = patient;
	}

	/**
	 * Pobranie daty i godziny zapisanej wizyty.
	 * 
	 * @return data i godzina zapisanej wizyty
	 */
	public Date getDate() {
		return date;
	}

	/**
	 * Ustawienie daty wizyty.
	 * 
	 * @param date data wizyty
	 */
	public void setDate(Date date) {
		this.date = date;
	}
	
	/**
	 * Pobranie czasu trwania wizyty.
	 * 
	 * @return czas trwania wizyty
	 */
	public Date getDuration() {
		return duration;
	}

	/**
	 * Ustawienie czasu trwania wizyty.
	 * 
	 * @param duration czas trwania wizyty
	 */
	public void setDuration(Date duration) {
		this.duration = duration;
	}

	/**
	 * Pobranie szacowanej godziny przyjęcia pacjenta.
	 * Godzina ta może zmieniać się zgodnie z czasem przyjęć poszczególnych pacjentów, jednak nigdy nie będzie wcześniejsza niż zapisany termin.
	 * 
	 * @return szacowana data i godzina przyjęcia pacjenta
	 */
	public Date getEstimatedEntry() {
		return estimatedEntry;
	}

	/**
	 * Ustawienie szacowanej godziny przyjęcia pacjenta.
	 * 
	 * @param estimatedEntry szacowana data i godzina przyjęcia pacjenta
	 */
	public void setEstimatedEntry(Date estimatedEntry) {
		this.estimatedEntry = estimatedEntry;
	}
	
	/**
	 * Czy wizyta nakłada się czasowo na drugą wizytę.
	 * 
	 * @param visit druga wizyta
	 * @return czy wizyty się nakładają
	 */
	public boolean isOverlapping(Visit visit){
		Calendar cal = Calendar.getInstance();
				
		cal.setTime(this.getDate());
		Date visitAStart = cal.getTime();
		cal.add(Calendar.MILLISECOND, (int)(this.getDuration().getTime() + cal.get(Calendar.ZONE_OFFSET) - cal.get(Calendar.DST_OFFSET))); //GMT conversion
		Date visitAEnd = cal.getTime();
		
		cal.setTime(visit.getDate());
		Date visitBStart = cal.getTime();
		cal.add(Calendar.MILLISECOND, (int)(visit.getDuration().getTime() + cal.get(Calendar.ZONE_OFFSET) - cal.get(Calendar.DST_OFFSET))); //GMT conversion
		Date visitBEnd = cal.getTime();
		
//		SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
//		System.out.println(dateFormat.format(visitAStart) + " - " + dateFormat.format(visitAEnd));
//		System.out.println(dateFormat.format(visitBStart) + " - " + dateFormat.format(visitBEnd));
		
		return ((visitAEnd.getTime() > visitBStart.getTime() && visitAStart.getTime() < visitBEnd.getTime()) 
				|| (visitAStart.getTime() == visitBStart.getTime()) 
				|| (visitAEnd.getTime() == visitBEnd.getTime()));
	}

	/**
	 * Konwersja obiektu wizyty na łatwy do zrozumienia łańcuch znaków.
	 * 
	 * @return sformatowany łańcuch znaków
	 */
	@Override
	public String toString() {
		String text = new String();
		
		SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
		
		text += "\nid:" + id + "\n" +
				((room != null) ? ("idRoom:" + room.getId() + "\n") : ("")) +
				"idPatient:" + patient.getId() + "\n" +
				"date:" + dateFormat.format(date) + "\n" +
				"duration:" + timeFormat.format(duration) + "\n" +
				"estimatedEntry:" + timeFormat.format(estimatedEntry);
		
		return text;
	}
}
